This is the final dataset and analysis that is referred to in the manuscript and Chapter 4.

Trying to get the order to be more chronological

Realistically, I should start from the beginning: 1. Remove all juveniles (except crameri, reedi, wilsoni) 2. Downsample the baseline to 32 samples per species. 3. Remove samples with scaled_likelihoood > 0.5 and z-score < -3

read in data and libraries

library(rubias)
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
library(tidyverse)
library(CKMRsim) # add this for the index markers function
# read in these filtered genotypes
new2col <- read_csv("csv_outputs/new2col.csv") %>%
  ungroup()
Parsed with column specification:
cols(
  .default = col_integer(),
  sample_type = col_character(),
  repunit = col_character(),
  collection = col_character(),
  indiv = col_character()
)
See spec(...) for full column specifications.
# new2col is made by the following steps in `05-cleaner-baseline.Rmd`
# new2col <- two_col %>%
# mutate(repunit = ifelse(indiv == "R035252", "caurinus", repunit)) %>%
# mutate(collection = ifelse(indiv == "R035252", "caurinus", collection)) %>%
# filter(!repunit %in% c("helvomaculatus", "simulator", "brevispinis"))
# raw genotypes
genos <- readRDS("../new_baseline_data/processed/called_genos_na_explicit.rds")
# genos1 <- genos %>% 
#   filter(!str_detect(NMFS_DNA_ID, "N")) # remove Lorne's ambiguous yelloweye samples
# labels <- readRDS("../new_baseline_data/processed/label-tibble.rds")
# samples <- readRDS("../new_baseline_data/processed/sample-sheet-tibble.rds")
# meta data
meta <- readRDS("../new_baseline_data/processed/meta-data-tibble.rds") %>%
  select(1,8,13,22) %>% # just the relevant columns for now
  mutate(REPORTED_LIFE_STAGE = ifelse(REPORTED_LIFE_STAGE == "Adult", "ADULT", REPORTED_LIFE_STAGE)) %>%   # make the syntax consistent
   mutate(REPORTED_LIFE_STAGE = ifelse(REPORTED_LIFE_STAGE == "Juvenile", "JUVENILE", REPORTED_LIFE_STAGE)) %>%
  mutate(REPORTED_LIFE_STAGE = ifelse(is.na(REPORTED_LIFE_STAGE), "UNKNOWN", REPORTED_LIFE_STAGE)) # be explict about NAs
# there are thousands of nmfs ids with two metadata entries
doubles <- meta %>%
  group_by(NMFS_DNA_ID) %>%
  tally() %>%
  filter(n > 1)
# remove one copy of each?
new2col

Remove juveniles

How many of those are juveniles?

juvies <- new2col %>%
  left_join(., meta, by = c("indiv" = "NMFS_DNA_ID")) %>%
  filter(REPORTED_LIFE_STAGE == "JUVENILE") %>%
  select(collection, indiv) %>%
  unique()
juv_samples <- juvies %>%
  group_by(collection) %>%
  tally() %>%
  rename(juv_samples = n)

There are 164 (?) juvenile samples

If I remove samples that are juveniles, what are my numbers per species?

new2col %>%
  semi_join(., meta, by = c("indiv" = "NMFS_DNA_ID")) %>%
  #anti_join(., juvies, by = "indiv") %>%
  group_by(collection) %>%
  tally() %>%
  rename(total_samples = n) %>%
  left_join(., juv_samples, by = "collection") %>%
  mutate(remaining_samples = total_samples-juv_samples) %>%
  arrange(remaining_samples)

We lose reedi and wilsoni when we exclude juveniles, and drop down to just 2 samples of crameri and five of serriceps.

However, generally including juveniles is a bad idea. So here’s what I’ll do: For any species for which we end up with fewer than 5 samples, I will include juveniles up to that number.

# just juvenile samples for these three species
juvs_to_keep <- new2col %>%
  ungroup() %>%
  filter(collection %in% c("reedi", "wilsoni", "crameri")) %>%
  left_join(., meta, by = c("indiv" = "NMFS_DNA_ID")) %>%
  group_by(collection) %>%
  filter(REPORTED_LIFE_STAGE == "JUVENILE") %>%
  select(1:184)

Now that I have those samples selected, I can remove all juvenile samples and put back those from the juvs_to_keep

dataset <- new2col %>%
  ungroup() %>%
  anti_join(juvies) %>%
  bind_rows(juvs_to_keep)
Joining, by = c("collection", "indiv")
dataset %>%
  group_by(repunit) %>%
  tally() %>%
  arrange(n) %>%
  write_csv("csv_outputs/dataset_spp_wo_juvs.csv")
  

Keeping just the juveniles from those three species, we have a total of 1,530 samples from 54 species.

Downsample

What if I take a maximum of 32 samples per species? (use set.seed to get reproducible results!)

# which species have fewer than 32 samples?
sm_grps <- dataset %>%
  group_by(collection) %>%
  tally() %>%
  arrange(n) %>%
  filter(n < 33)
# make a 2-col dataframe with just those groups
sm_d2 <- dataset %>%
  semi_join(., sm_grps) %>%
  ungroup()
Joining, by = "collection"
# which species have more than 32 samples?
lrg_grps <- dataset %>%
  group_by(collection) %>%
  tally() %>%
  arrange(n) %>%
  filter(n > 32)
  
# downsample those groups
set.seed(5)
down_sam <- dataset %>%
  semi_join(., lrg_grps) %>%
  group_by(collection) %>%
  sample_n(., 32, replace = FALSE) %>%
  ungroup()
Joining, by = "collection"
# finish the set.seed
set.seed(NULL)
# and add the data from the other groups back into the dataframe
down_data <- sm_d2 %>%
  bind_rows(down_sam) #%>%
  # group_by(collection) %>%
  # tally() %>%
  # arrange(n)

1010 total samples 54 species

Self-assignment

Now do the self-assignment:

assign_down <- self_assign(down_data, gen_start_col = 5)
Summary Statistics:

1010 Individuals in Sample

90 Loci: Plate_1_A01_Sat_GW603857_consensus.1, Plate_1_A11_Sat_GE820299_consensus.1, Plate_2_A09_Sat_EW986980_consensus.1, Plate_2_C08_Sat_EW987116_consensus.1, Plate_2_G06_Sat_EW987118_consensus.1, Plate_3_C03_Sat_GE798118_consensus.1, Plate_4_E10_Sat_EW976030_consensus.1, Plate_4_G06_Sat_EW976181_consensus.1, tag_id_1049.1, tag_id_108.1, tag_id_1184.1, tag_id_1229.1, tag_id_1272.1, tag_id_1366.1, tag_id_1428.1, tag_id_143.1, tag_id_1441.1, tag_id_1449.1, tag_id_1471.1, tag_id_1498.1, tag_id_1558.1, tag_id_1576.1, tag_id_1598.1, tag_id_1604.1, tag_id_1613.1, tag_id_162.1, tag_id_1652.1, tag_id_170.1, tag_id_1708.1, tag_id_1748.1, tag_id_1751.1, tag_id_1762.1, tag_id_179.1, tag_id_1804.1, tag_id_1808.1, tag_id_1810.1, tag_id_1836.1, tag_id_1850.1, tag_id_1880.1, tag_id_1889.1, tag_id_1915.1, tag_id_1950.1, tag_id_1961.1, tag_id_1966.1, tag_id_1982.1, tag_id_1994.1, tag_id_1999.1, tag_id_2008.1, tag_id_2009.1, tag_id_2017.1, tag_id_2062.1, tag_id_2082.1, tag_id_2114.1, tag_id_2134.1, tag_id_2155.1, tag_id_2178.1, tag_id_2182.1, tag_id_220.1, tag_id_2203.1, tag_id_221.1, tag_id_2214.1, tag_id_2237.1, tag_id_2247.1, tag_id_2258.1, tag_id_2301.1, tag_id_2319.1, tag_id_2368.1, tag_id_2499.1, tag_id_250.1, tag_id_2607.1, tag_id_2635.1, tag_id_265.1, tag_id_325.1, tag_id_402.1, tag_id_410.1, tag_id_436.1, tag_id_55.1, tag_id_572.1, tag_id_67.1, tag_id_770.1, tag_id_788.1, tag_id_843.1, tag_id_855.1, tag_id_874.1, tag_id_875.1, tag_id_879.1, tag_id_913.1, tag_id_942.1, tag_id_981.1, tag_id_987.1

54 Reporting Units: aleutianus, alutus, auriculatus, aurora, babcocki, borealis, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, hopkinsi, jordani, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, paucispinis, pinniger, polyspinis, proriger, rastrelliger, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serriceps, umbrosus, zacentrus, reedi, wilsoni, atrovirens, carnatus, chrysomelas, goodei, levis, ovalis, serranoides

54 Collections: aleutianus, alutus, auriculatus, aurora, babcocki, borealis, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, hopkinsi, jordani, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, paucispinis, pinniger, polyspinis, proriger, rastrelliger, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serriceps, umbrosus, zacentrus, reedi, wilsoni, atrovirens, carnatus, chrysomelas, goodei, levis, ovalis, serranoides

8.52145214521452% of allelic data identified as missing

Assignment accuracy?

assign_down %>%
  ungroup() %>%
  filter(scaled_likelihood > 0.95) %>%
  mutate(accurate = if_else(repunit == inferred_repunit, TRUE, FALSE)) %>%
  filter(accurate == TRUE) #%>%
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
  #filter(collection == "carnatus")
993/1010
[1] 0.9831683

z-scores?

z_outliers <- assign_down %>%
  filter(scaled_likelihood > 0.5 & z_score < -3) %>%
  arrange(z_score)
z_outliers

There are 10 samples with z-scores < -3, including 5 hopkinsi samples.

Let’s remove those.

Removing those leaves us with 1000 samples.

Mixture assignment with outliers?

Just to test it out, I’m going to remove these outliers from the baseline and then perform rubias’s mixture assignment with them.

# reference
down_data2 <- down_data2 %>%
  ungroup()
# outliers for mixture assignment
zs <- z_outliers %>%
  select(indiv)
just_zs <- down_data %>%
  ungroup() %>%
  right_join(., zs) %>%
  mutate(sample_type = "mixture")
Joining, by = "indiv"

Now that the data are separated and formatted, do the mixture assignment

mix_zs <- infer_mixture(reference = down_data2, mixture = just_zs, gen_start_col = 5)
Collating data; compiling reference allele frequencies, etc.   time: 0.56 seconds
Computing reference locus specific means and variances for computing mixture z-scores   time: 0.28 seconds
Working on mixture collection: flavidus with 1 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.00 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 0.25 seconds
  tidying output into a tibble.   time: 0.03 seconds
Working on mixture collection: hopkinsi with 5 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.00 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 0.27 seconds
  tidying output into a tibble.   time: 0.03 seconds
Working on mixture collection: melanops with 1 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.00 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 0.24 seconds
  tidying output into a tibble.   time: 0.03 seconds
Working on mixture collection: nigrocinctus with 1 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.00 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 0.24 seconds
  tidying output into a tibble.   time: 0.03 seconds
Working on mixture collection: umbrosus with 1 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.00 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 0.23 seconds
  tidying output into a tibble.   time: 0.03 seconds
Working on mixture collection: ovalis with 1 individuals
  calculating log-likelihoods of the mixture individuals.   time: 0.00 seconds
  performing 100 burn-in and 2000 more sweeps of method "MCMC"   time: 0.23 seconds
  tidying output into a tibble.   time: 0.03 seconds
mix_zs$indiv_posteriors %>%
  filter(PofZ > 0.50)
NA

Interesting! One of the hopkinsi comes up as caurinus… but with a z-score of -14! What is it?? The z-scores for the other fish are also pretty extraordinary (none are within 2 standard deviations of the mean).

Take a quick look at the three additional hopkinsi in mixture assignment:

mix2
$mixing_proportions

$indiv_posteriors

$mix_prop_traces

$bootstrapped_proportions
NA

Take a look at those results

Wild! So three of the hopkinsi assign to caurinus, but with really really low z-scores. I think this is actually interesting enough to include as a small analysis in the methods/results.

In addition, let’s create a single reporting unit for gopher/black-and-yellow

single GBY reporting unit

Since all of the misassignments are GBY, make a single reporting unit.

# change the carnatus reporting unit to chrysomelas
gby_repu_2col <- down_data2 %>%
  mutate(repunit = ifelse(repunit == "carnatus", "chrysomelas", repunit))
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
# confirm that the repunit is changed but the collection is not.
gby_repu_2col %>%
  filter(collection == "carnatus")

Now try self-assignment with the single reporting unit

gby_repu_assigned <- gby_repu_2col %>%
  self_assign(., gen_start_col = 5)
Summary Statistics:

1000 Individuals in Sample

90 Loci: Plate_1_A01_Sat_GW603857_consensus.1, Plate_1_A11_Sat_GE820299_consensus.1, Plate_2_A09_Sat_EW986980_consensus.1, Plate_2_C08_Sat_EW987116_consensus.1, Plate_2_G06_Sat_EW987118_consensus.1, Plate_3_C03_Sat_GE798118_consensus.1, Plate_4_E10_Sat_EW976030_consensus.1, Plate_4_G06_Sat_EW976181_consensus.1, tag_id_1049.1, tag_id_108.1, tag_id_1184.1, tag_id_1229.1, tag_id_1272.1, tag_id_1366.1, tag_id_1428.1, tag_id_143.1, tag_id_1441.1, tag_id_1449.1, tag_id_1471.1, tag_id_1498.1, tag_id_1558.1, tag_id_1576.1, tag_id_1598.1, tag_id_1604.1, tag_id_1613.1, tag_id_162.1, tag_id_1652.1, tag_id_170.1, tag_id_1708.1, tag_id_1748.1, tag_id_1751.1, tag_id_1762.1, tag_id_179.1, tag_id_1804.1, tag_id_1808.1, tag_id_1810.1, tag_id_1836.1, tag_id_1850.1, tag_id_1880.1, tag_id_1889.1, tag_id_1915.1, tag_id_1950.1, tag_id_1961.1, tag_id_1966.1, tag_id_1982.1, tag_id_1994.1, tag_id_1999.1, tag_id_2008.1, tag_id_2009.1, tag_id_2017.1, tag_id_2062.1, tag_id_2082.1, tag_id_2114.1, tag_id_2134.1, tag_id_2155.1, tag_id_2178.1, tag_id_2182.1, tag_id_220.1, tag_id_2203.1, tag_id_221.1, tag_id_2214.1, tag_id_2237.1, tag_id_2247.1, tag_id_2258.1, tag_id_2301.1, tag_id_2319.1, tag_id_2368.1, tag_id_2499.1, tag_id_250.1, tag_id_2607.1, tag_id_2635.1, tag_id_265.1, tag_id_325.1, tag_id_402.1, tag_id_410.1, tag_id_436.1, tag_id_55.1, tag_id_572.1, tag_id_67.1, tag_id_770.1, tag_id_788.1, tag_id_843.1, tag_id_855.1, tag_id_874.1, tag_id_875.1, tag_id_879.1, tag_id_913.1, tag_id_942.1, tag_id_981.1, tag_id_987.1

53 Reporting Units: aleutianus, alutus, auriculatus, aurora, babcocki, borealis, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, hopkinsi, jordani, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, paucispinis, pinniger, polyspinis, proriger, rastrelliger, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serriceps, umbrosus, zacentrus, reedi, wilsoni, atrovirens, chrysomelas, goodei, levis, ovalis, serranoides

54 Collections: aleutianus, alutus, auriculatus, aurora, babcocki, borealis, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, hopkinsi, jordani, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, paucispinis, pinniger, polyspinis, proriger, rastrelliger, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serriceps, umbrosus, zacentrus, reedi, wilsoni, atrovirens, carnatus, chrysomelas, goodei, levis, ovalis, serranoides

8.55666666666667% of allelic data identified as missing

Accuracy?

gby_repu_assigned %>%
  filter(scaled_likelihood > 0.95) %>%
  filter(repunit == inferred_repunit)
992/1000
gby_repu_assigned %>%
  filter(scaled_likelihood > 0.5 & scaled_likelihood < 0.95)

All assignments below the 95% threshold were gopher/black-and-yellow.

What about z-statistics?

Three additional hopkinsi, as before.

What were the z-scores for these hopkinsi in the previous self-assignment?

assign_down %>%
  ungroup() %>%
  filter(scaled_likelihood > 0.5 & repunit == "hopkinsi") %>%
  arrange(z_score) %>%
  select(indiv, z_score) %>%
  ungroup()

Not sure what to do about this. Should I have left in the three hopkinsi that only became problematic the second time around? Or can I justify iterating because the z-statistic is based on the mean of the data, so if I have changed the genotypes that are valid hopkinsi, then the mean has changed, and thus, it is unsurprising that additional samples are now outliers.

To be conservative, I think it makes some sense to remove these additional three fish.

Once more, after removing those hopkinsi

down_data3 <- gby_repu_2col %>%
  ungroup() %>%
  anti_join(., outies, by = "indiv")

Self-assignment once again, to test whether we can actually eliminate the samples with z-statistics < -3

assigned3 <- self_assign(down_data3, gen_start_col = 5)
Summary Statistics:

997 Individuals in Sample

90 Loci: Plate_1_A01_Sat_GW603857_consensus.1, Plate_1_A11_Sat_GE820299_consensus.1, Plate_2_A09_Sat_EW986980_consensus.1, Plate_2_C08_Sat_EW987116_consensus.1, Plate_2_G06_Sat_EW987118_consensus.1, Plate_3_C03_Sat_GE798118_consensus.1, Plate_4_E10_Sat_EW976030_consensus.1, Plate_4_G06_Sat_EW976181_consensus.1, tag_id_1049.1, tag_id_108.1, tag_id_1184.1, tag_id_1229.1, tag_id_1272.1, tag_id_1366.1, tag_id_1428.1, tag_id_143.1, tag_id_1441.1, tag_id_1449.1, tag_id_1471.1, tag_id_1498.1, tag_id_1558.1, tag_id_1576.1, tag_id_1598.1, tag_id_1604.1, tag_id_1613.1, tag_id_162.1, tag_id_1652.1, tag_id_170.1, tag_id_1708.1, tag_id_1748.1, tag_id_1751.1, tag_id_1762.1, tag_id_179.1, tag_id_1804.1, tag_id_1808.1, tag_id_1810.1, tag_id_1836.1, tag_id_1850.1, tag_id_1880.1, tag_id_1889.1, tag_id_1915.1, tag_id_1950.1, tag_id_1961.1, tag_id_1966.1, tag_id_1982.1, tag_id_1994.1, tag_id_1999.1, tag_id_2008.1, tag_id_2009.1, tag_id_2017.1, tag_id_2062.1, tag_id_2082.1, tag_id_2114.1, tag_id_2134.1, tag_id_2155.1, tag_id_2178.1, tag_id_2182.1, tag_id_220.1, tag_id_2203.1, tag_id_221.1, tag_id_2214.1, tag_id_2237.1, tag_id_2247.1, tag_id_2258.1, tag_id_2301.1, tag_id_2319.1, tag_id_2368.1, tag_id_2499.1, tag_id_250.1, tag_id_2607.1, tag_id_2635.1, tag_id_265.1, tag_id_325.1, tag_id_402.1, tag_id_410.1, tag_id_436.1, tag_id_55.1, tag_id_572.1, tag_id_67.1, tag_id_770.1, tag_id_788.1, tag_id_843.1, tag_id_855.1, tag_id_874.1, tag_id_875.1, tag_id_879.1, tag_id_913.1, tag_id_942.1, tag_id_981.1, tag_id_987.1

53 Reporting Units: aleutianus, alutus, auriculatus, aurora, babcocki, borealis, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, hopkinsi, jordani, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, paucispinis, pinniger, polyspinis, proriger, rastrelliger, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serriceps, umbrosus, zacentrus, reedi, wilsoni, atrovirens, chrysomelas, goodei, levis, ovalis, serranoides

54 Collections: aleutianus, alutus, auriculatus, aurora, babcocki, borealis, caurinus, chlorostictus, constellatus, crameri, dallii, diaconus, diploproa, elongatus, emphaeus, ensifer, entomelas, flavidus, hopkinsi, jordani, maliger, melanops, melanostictus, melanostomus, miniatus, moseri, mystinus, nebulosus, nigrocinctus, oculatus, paucispinis, pinniger, polyspinis, proriger, rastrelliger, rosaceus, ruberrimus, rubrivinctus, rufinanus, rufus, saxicola, semicinctus, serriceps, umbrosus, zacentrus, reedi, wilsoni, atrovirens, carnatus, chrysomelas, goodei, levis, ovalis, serranoides

8.5712693636465% of allelic data identified as missing

Check the assignments and check the z-scores

assigned3 %>%
  filter(scaled_likelihood > 0.5 & z_score < -3)
Warning in `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows

Cool, so there is a point at which the samples are all falling within the expected distribution of “accurate” assignments.

Phylogenetic trees

Let’s grab information for those samples so that I can make the trees with them.

997 samples in total.

Read in genotype data with the GTseq run number and the sample ids

genos <- readRDS("../new_baseline_data/processed/called_genos_na_explicit.rds")

genos_gtseq <- genos %>%
  ungroup() %>%
  select(NMFS_DNA_ID, gtseq_run, id) %>%
  ungroup()
clean_samples %>%
  left_join(., genos_gtseq, by = c("indiv" = "NMFS_DNA_ID")) %>%
  group_by(collection) %>%
  unique() %>%
  arrange(indiv) %>%
  select(indiv) %>%
  ungroup() %>%
  group_by(indiv) %>%
  tally() %>%
  arrange(desc(n))
Adding missing grouping variables: `collection`
NA

For building the phylogenetic trees, I need a list of samples and GTseq runs to use for Freebayes. And for samples that were genotyped twice, I want to choose the “best” genotype.

NOTE: these are NOT duplicates within my self-assignment dataset, they are duplicates in called_genos_na_explicit.rds

duplicates <- c("R001570","R011993","R012111","R012125", "R012201")
Warning messages:
1: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
2: In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
dupl <- as.tibble(duplicates)
dups <- dupl %>%
  rename(NMFS_DNA_ID = value)

Check out the duplicate genotypes

dup_genos <- dups %>%
  left_join(., genos) %>%
  ungroup()

Now take the genotype with the highest total read depth.

# slow-ish function to get the total read depth column
tdepth <- function(a, d) {
  if(any(is.na(a))) {
    return(NA)
  }
  if(a[1]==a[2]) {
    return(d[1])
  } else {
    return(d[1] + d[2])
  }
  
}
# this takes the highest read-depth instance of each duplicately-genotyped individual.
one_each <- dup_genos %>%
  group_by(NMFS_DNA_ID, locus, gtseq_run) %>%
  mutate(total_depth = tdepth(allele, depth)) %>%
  ungroup() %>%
  arrange(NMFS_DNA_ID, locus, total_depth, gtseq_run, depth) %>%
  group_by(NMFS_DNA_ID, locus) %>%
  mutate(rank = 1:n()) %>% 
  #ungroup() %>%
  filter(rank <= 2)

Confirm that there’s only one instance of each sample, and look at the gtseq run and id info here

one_dup <- one_each %>%
  group_by(NMFS_DNA_ID, gtseq_run, id) %>%
  tally() %>%
  filter(n < 100) # choose the sample with fewer high-read-depth loci to remove

one_dup

Okay, now remove those samples, which should leave us with our dataset for building trees.

clean_samples %>%
  left_join(., genos_gtseq, by = c("indiv" = "NMFS_DNA_ID")) %>%
  anti_join(., one_dup) %>%
  unique() %>%
  arrange(collection) %>%
  write_csv("csv_outputs/clean_gtseq_ids_for_trees.csv")

calculate and plot int hz for each species

I want to use this same dataset of 997 individuals for calculating int-hz.

t1 <- clean_samples %>%
  left_join(down_data3) %>%
  group_by(indiv, collection) %>%
  select(-sample_type, -repunit) %>%
  gather(locus, allele, 3:182) %>%
  ungroup() %>% # need to remove the .1 and .2 on the loci
  separate(locus, c("Locus", "gene.copy"), sep = "[.]")
Joining, by = c("indiv", "collection")
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows

What about making a series of boxplots?

I want to set the species phylogenetically rather than alphabetically:

# set the levels explicitly
int_hz$collection <- factor(int_hz$collection, levels = c("atrovirens", "chrysomelas", "carnatus", "caurinus", "maliger", "nebulosus", "dallii","rastrelliger", "auriculatus", "saxicola", "semicinctus", "elongatus", "miniatus", "pinniger", "oculatus", "constellatus", "umbrosus", "rosaceus", "chlorostictus", "ensifer", "babcocki", "nigrocinctus", "rubrivinctus", "serriceps", "rufus", "ovalis", "hopkinsi", "rufinanus", "moseri", "jordani", "paucispinis", "goodei", "levis", "entomelas", "mystinus", "diaconus", "flavidus", "serranoides", "melanops", "ruberrimus", "aurora", "diploproa", "melanostomus", "reedi", "crameri", "polyspinis", "alutus", "melanostictus", "aleutianus", "emphaeus", "wilsoni", "zacentrus", "proriger", "borealis"))
Warning message:
In `[<-.data.frame`(`*tmp*`, is_list, value = list(`11` = "<>")) :
  replacement element 1 has 1 row to replace 0 rows
# check that the levels stuck
levels(int_hz$collection)
 [1] "atrovirens"    "chrysomelas"   "carnatus"      "caurinus"      "maliger"      
 [6] "nebulosus"     "dallii"        "rastrelliger"  "auriculatus"   "saxicola"     
[11] "semicinctus"   "elongatus"     "miniatus"      "pinniger"      "oculatus"     
[16] "constellatus"  "umbrosus"      "rosaceus"      "chlorostictus" "ensifer"      
[21] "babcocki"      "nigrocinctus"  "rubrivinctus"  "serriceps"     "rufus"        
[26] "ovalis"        "hopkinsi"      "rufinanus"     "moseri"        "jordani"      
[31] "paucispinis"   "goodei"        "levis"         "entomelas"     "mystinus"     
[36] "diaconus"      "flavidus"      "serranoides"   "melanops"      "ruberrimus"   
[41] "aurora"        "diploproa"     "melanostomus"  "reedi"         "crameri"      
[46] "polyspinis"    "alutus"        "melanostictus" "aleutianus"    "emphaeus"     
[51] "wilsoni"       "zacentrus"     "proriger"      "borealis"     
# now boxplot it
box2 <- ggplot(int_hz) +
  geom_boxplot(aes(x = collection, y = fract_hz), position = "dodge") +
  theme_bw() +
  xlab("Species") +
  ylab("Internal heterozygosity")
box2 +
  theme(
    axis.text.x = element_text(angle = 90, size = 12),
    axis.text.y = element_text(size = 12),
    axis.title = element_text(size = 14)
  ) +
  guides(fill = FALSE)
ggsave("pdf_outputs/clean_int-hz-boxplot.pdf", height = 8, width = 10)

Summary Statistics The lower and upper hinges correspond to the first and third quartiles (the 25th and 75th percentiles).

The upper whisker extends from the hinge to the largest value no further than 1.5 x IQR from the hinge (where IQR is the inter-quartile range, or distance between the first and third quartiles). The lower whisker extends from the hinge to the smallest value at most 1.5 x IQR of the hinge. Data beyond the end of the whiskers are called “outlying” points and are plotted individually. Now what about adding in the subgenera and coloring the boxes by that?

Make a list of subgenera and species and read that in

subgenera <- read_csv("../data/sebastes_subgenera.csv") %>%
  ungroup()
Parsed with column specification:
cols(
  species = col_character(),
  subgenus = col_character(),
  Li_etal = col_character()
)
  
int_hz_subg <- int_hz %>%
  ungroup() %>%
  left_join(., subgenera, by = c("collection" = "species"))
Column `collection`/`species` joining factor and character vector, coercing into character vector
# and set the levels explicitly again
int_hz_subg$collection <- factor(int_hz_subg$collection, levels = c("atrovirens", "chrysomelas", "carnatus", "caurinus", "maliger", "nebulosus", "dallii","rastrelliger", "auriculatus", "saxicola", "emphaeus", "wilsoni", "zacentrus", "proriger", "semicinctus", "rubrivinctus", "levis", "elongatus", "miniatus", "pinniger", "babcocki", "oculatus", "constellatus", "umbrosus", "rosaceus", "chlorostictus", "rufus", "ensifer", "diploproa", "nigrocinctus", "serriceps", "ovalis", "hopkinsi", "rufinanus", "moseri", "entomelas", "alutus", "jordani", "paucispinis", "goodei", "mystinus", "diaconus", "flavidus", "serranoides", "melanops", "ruberrimus", "aurora", "melanostomus", "crameri", "melanostictus", "aleutianus", "borealis", "reedi", "polyspinis"))
# check that the levels stuck
#levels(int_hz_subg$collection)

Try coloring the boxplot by the subgenera

I need to confirm the subgenera affiliations, but I think that could end up looking pretty cool. I ended up using a combo of Li et al. 2007, Kendall 2000, and Hyde and Vetter 2007.

Change the colors:

library(RColorBrewer)
mycolors = colorRampPalette(brewer.pal(name="Accent", n = 8))(14)
  
#mycolors = c(brewer.pal(name="Set1", n = 6), brewer.pal(name="Set2", n = 8))

Set the subgenera to the order of the factor (species)

int_hz2 <- int_hz_subg %>%
  ungroup()
int_hz2$subgenus <- factor(int_hz2$subgenus, levels = c("Pteropodus", "Allosebastes", "Hispaniscus", "Rosicola", "Sebastomus", "Sebastichthys", "Sebastocarus", "Acutomentum", "Sebastodes", "Sebastosomus", "Sebastopyr", "Eosebastes", "Zalopyr", "unclassified"))
# now boxplot it
box3 <- ggplot(int_hz2) +
  geom_boxplot(aes(x = collection, y = fract_hz, fill = subgenus), position = "dodge") +
  theme_bw() +
  xlab("Species") +
  ylab("Internal heterozygosity") +
  scale_fill_manual(values = mycolors)
box3 +
  theme(
    axis.text.x = element_text(angle = 90, size = 12),
    axis.text.y = element_text(size = 12),
    axis.title = element_text(size = 14)
  )
#+
  #guides(fill = FALSE) 
ggsave("pdf_outputs/int-hz-boxplot-subgenera_v2.pdf", height = 8, width = 10)

We could also imagine ordering the species according to their internal heterozygosity:

library(forcats)
box4 <- int_hz2 %>%
  ggplot(aes(x = fct_reorder(collection, fract_hz, fun = median, .desc =TRUE), fract_hz, fill = subgenus)) +
  geom_boxplot(position = "dodge") +
  theme_bw() +
  xlab("Species") +
  ylab("Internal heterozygosity") +
  scale_fill_manual(values = mycolors)
box4 +
  theme(
    axis.text.x = element_text(angle = 90, size = 12),
    axis.text.y = element_text(size = 12),
    axis.title = element_text(size = 14)
  ) #+
  #guides(fill = FALSE)
ggsave("pdf_outputs/int-hz-boxplot-ordered.pdf", height = 8, width = 10)

Calculate the reduction in heterozygosity in comparison to S. atrovirens

int_hz %>%
  group_by(collection) %>%
  summarise(ave_hz = mean(fract_hz)) %>%
  arrange(desc(ave_hz)) %>%
  mutate(diff_hz = (0.45781055-ave_hz))

S. chrysomelas retains the greatest hz (0.409) whereas S. rubrivinctus has the smallest amount of variation at these markers (0.012).

LS0tCnRpdGxlOiAiZG93bnNhbXBsZWQgYmFzZWxpbmUiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KVGhpcyBpcyB0aGUgZmluYWwgZGF0YXNldCBhbmQgYW5hbHlzaXMgdGhhdCBpcyByZWZlcnJlZCB0byBpbiB0aGUgbWFudXNjcmlwdCBhbmQgQ2hhcHRlciA0LgoKIyMgVHJ5aW5nIHRvIGdldCB0aGUgb3JkZXIgdG8gYmUgbW9yZSBjaHJvbm9sb2dpY2FsClJlYWxpc3RpY2FsbHksIEkgc2hvdWxkIHN0YXJ0IGZyb20gdGhlIGJlZ2lubmluZzogCjEuIFJlbW92ZSBhbGwganV2ZW5pbGVzIChleGNlcHQgY3JhbWVyaSwgcmVlZGksIHdpbHNvbmkpCjIuIERvd25zYW1wbGUgdGhlIGJhc2VsaW5lIHRvIDMyIHNhbXBsZXMgcGVyIHNwZWNpZXMuCjMuIFJlbW92ZSBzYW1wbGVzIHdpdGggc2NhbGVkX2xpa2VsaWhvb29kID4gMC41IGFuZCB6LXNjb3JlIDwgLTMKCgpyZWFkIGluIGRhdGEgYW5kIGxpYnJhcmllcwpgYGB7cn0KbGlicmFyeShydWJpYXMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KENLTVJzaW0pICMgYWRkIHRoaXMgZm9yIHRoZSBpbmRleCBtYXJrZXJzIGZ1bmN0aW9uCgojIHJlYWQgaW4gdGhlc2UgZmlsdGVyZWQgZ2Vub3R5cGVzCm5ldzJjb2wgPC0gcmVhZF9jc3YoImNzdl9vdXRwdXRzL25ldzJjb2wuY3N2IikgJT4lCiAgdW5ncm91cCgpCgojIG5ldzJjb2wgaXMgbWFkZSBieSB0aGUgZm9sbG93aW5nIHN0ZXBzIGluIGAwNS1jbGVhbmVyLWJhc2VsaW5lLlJtZGAKIyBuZXcyY29sIDwtIHR3b19jb2wgJT4lCiMgbXV0YXRlKHJlcHVuaXQgPSBpZmVsc2UoaW5kaXYgPT0gIlIwMzUyNTIiLCAiY2F1cmludXMiLCByZXB1bml0KSkgJT4lCiMgbXV0YXRlKGNvbGxlY3Rpb24gPSBpZmVsc2UoaW5kaXYgPT0gIlIwMzUyNTIiLCAiY2F1cmludXMiLCBjb2xsZWN0aW9uKSkgJT4lCiMgZmlsdGVyKCFyZXB1bml0ICVpbiUgYygiaGVsdm9tYWN1bGF0dXMiLCAic2ltdWxhdG9yIiwgImJyZXZpc3BpbmlzIikpCgojIHJhdyBnZW5vdHlwZXMKZ2Vub3MgPC0gcmVhZFJEUygiLi4vbmV3X2Jhc2VsaW5lX2RhdGEvcHJvY2Vzc2VkL2NhbGxlZF9nZW5vc19uYV9leHBsaWNpdC5yZHMiKQojIGdlbm9zMSA8LSBnZW5vcyAlPiUgCiMgICBmaWx0ZXIoIXN0cl9kZXRlY3QoTk1GU19ETkFfSUQsICJOIikpICMgcmVtb3ZlIExvcm5lJ3MgYW1iaWd1b3VzIHllbGxvd2V5ZSBzYW1wbGVzCiMgbGFiZWxzIDwtIHJlYWRSRFMoIi4uL25ld19iYXNlbGluZV9kYXRhL3Byb2Nlc3NlZC9sYWJlbC10aWJibGUucmRzIikKIyBzYW1wbGVzIDwtIHJlYWRSRFMoIi4uL25ld19iYXNlbGluZV9kYXRhL3Byb2Nlc3NlZC9zYW1wbGUtc2hlZXQtdGliYmxlLnJkcyIpCgojIG1ldGEgZGF0YQptZXRhIDwtIHJlYWRSRFMoIi4uL25ld19iYXNlbGluZV9kYXRhL3Byb2Nlc3NlZC9tZXRhLWRhdGEtdGliYmxlLnJkcyIpICU+JQogIHNlbGVjdCgxLDgsMTMsMjIpICU+JSAjIGp1c3QgdGhlIHJlbGV2YW50IGNvbHVtbnMgZm9yIG5vdwogIG11dGF0ZShSRVBPUlRFRF9MSUZFX1NUQUdFID0gaWZlbHNlKFJFUE9SVEVEX0xJRkVfU1RBR0UgPT0gIkFkdWx0IiwgIkFEVUxUIiwgUkVQT1JURURfTElGRV9TVEFHRSkpICU+JSAgICMgbWFrZSB0aGUgc3ludGF4IGNvbnNpc3RlbnQKICAgbXV0YXRlKFJFUE9SVEVEX0xJRkVfU1RBR0UgPSBpZmVsc2UoUkVQT1JURURfTElGRV9TVEFHRSA9PSAiSnV2ZW5pbGUiLCAiSlVWRU5JTEUiLCBSRVBPUlRFRF9MSUZFX1NUQUdFKSkgJT4lCiAgbXV0YXRlKFJFUE9SVEVEX0xJRkVfU1RBR0UgPSBpZmVsc2UoaXMubmEoUkVQT1JURURfTElGRV9TVEFHRSksICJVTktOT1dOIiwgUkVQT1JURURfTElGRV9TVEFHRSkpICMgYmUgZXhwbGljdCBhYm91dCBOQXMKCiMgdGhlcmUgYXJlIHRob3VzYW5kcyBvZiBubWZzIGlkcyB3aXRoIHR3byBtZXRhZGF0YSBlbnRyaWVzCmRvdWJsZXMgPC0gbWV0YSAlPiUKICBncm91cF9ieShOTUZTX0ROQV9JRCkgJT4lCiAgdGFsbHkoKSAlPiUKICBmaWx0ZXIobiA+IDEpCgojIHJlbW92ZSBvbmUgY29weSBvZiBlYWNoPwoKbmV3MmNvbApgYGAKCgojIyBSZW1vdmUganV2ZW5pbGVzCgpIb3cgbWFueSBvZiB0aG9zZSBhcmUganV2ZW5pbGVzPwpgYGB7cn0KanV2aWVzIDwtIG5ldzJjb2wgJT4lCiAgbGVmdF9qb2luKC4sIG1ldGEsIGJ5ID0gYygiaW5kaXYiID0gIk5NRlNfRE5BX0lEIikpICU+JQogIGZpbHRlcihSRVBPUlRFRF9MSUZFX1NUQUdFID09ICJKVVZFTklMRSIpICU+JQogIHNlbGVjdChjb2xsZWN0aW9uLCBpbmRpdikgJT4lCiAgdW5pcXVlKCkKCmp1dl9zYW1wbGVzIDwtIGp1dmllcyAlPiUKICBncm91cF9ieShjb2xsZWN0aW9uKSAlPiUKICB0YWxseSgpICU+JQogIHJlbmFtZShqdXZfc2FtcGxlcyA9IG4pCmBgYApUaGVyZSBhcmUgMTY0ICg/KSBqdXZlbmlsZSBzYW1wbGVzCgpJZiBJIHJlbW92ZSBzYW1wbGVzIHRoYXQgYXJlIGp1dmVuaWxlcywgd2hhdCBhcmUgbXkgbnVtYmVycyBwZXIgc3BlY2llcz8KYGBge3J9Cm5ldzJjb2wgJT4lCiAgc2VtaV9qb2luKC4sIG1ldGEsIGJ5ID0gYygiaW5kaXYiID0gIk5NRlNfRE5BX0lEIikpICU+JQogICNhbnRpX2pvaW4oLiwganV2aWVzLCBieSA9ICJpbmRpdiIpICU+JQogIGdyb3VwX2J5KGNvbGxlY3Rpb24pICU+JQogIHRhbGx5KCkgJT4lCiAgcmVuYW1lKHRvdGFsX3NhbXBsZXMgPSBuKSAlPiUKICBsZWZ0X2pvaW4oLiwganV2X3NhbXBsZXMsIGJ5ID0gImNvbGxlY3Rpb24iKSAlPiUKICBtdXRhdGUocmVtYWluaW5nX3NhbXBsZXMgPSB0b3RhbF9zYW1wbGVzLWp1dl9zYW1wbGVzKSAlPiUKICBhcnJhbmdlKHJlbWFpbmluZ19zYW1wbGVzKQoKYGBgCldlIGxvc2UgcmVlZGkgYW5kIHdpbHNvbmkgd2hlbiB3ZSBleGNsdWRlIGp1dmVuaWxlcywgYW5kIGRyb3AgZG93biB0byBqdXN0IDIgc2FtcGxlcyBvZiBjcmFtZXJpIGFuZCBmaXZlIG9mIHNlcnJpY2Vwcy4KCkhvd2V2ZXIsIGdlbmVyYWxseSBpbmNsdWRpbmcganV2ZW5pbGVzIGlzIGEgYmFkIGlkZWEuIFNvIGhlcmUncyB3aGF0IEknbGwgZG86IEZvciBhbnkgc3BlY2llcyBmb3Igd2hpY2ggd2UgZW5kIHVwIHdpdGggZmV3ZXIgdGhhbiA1IHNhbXBsZXMsIEkgd2lsbCBpbmNsdWRlIGp1dmVuaWxlcyB1cCB0byB0aGF0IG51bWJlci4KCmBgYHtyfQojIGp1c3QganV2ZW5pbGUgc2FtcGxlcyBmb3IgdGhlc2UgdGhyZWUgc3BlY2llcwpqdXZzX3RvX2tlZXAgPC0gbmV3MmNvbCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKGNvbGxlY3Rpb24gJWluJSBjKCJyZWVkaSIsICJ3aWxzb25pIiwgImNyYW1lcmkiKSkgJT4lCiAgbGVmdF9qb2luKC4sIG1ldGEsIGJ5ID0gYygiaW5kaXYiID0gIk5NRlNfRE5BX0lEIikpICU+JQogIGdyb3VwX2J5KGNvbGxlY3Rpb24pICU+JQogIGZpbHRlcihSRVBPUlRFRF9MSUZFX1NUQUdFID09ICJKVVZFTklMRSIpICU+JQogIHNlbGVjdCgxOjE4NCkKCmBgYAoKTm93IHRoYXQgSSBoYXZlIHRob3NlIHNhbXBsZXMgc2VsZWN0ZWQsIEkgY2FuIHJlbW92ZSBhbGwganV2ZW5pbGUgc2FtcGxlcyBhbmQgcHV0IGJhY2sgdGhvc2UgZnJvbSB0aGUgYGp1dnNfdG9fa2VlcGAKYGBge3J9CmRhdGFzZXQgPC0gbmV3MmNvbCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYW50aV9qb2luKGp1dmllcykgJT4lCiAgYmluZF9yb3dzKGp1dnNfdG9fa2VlcCkKCmRhdGFzZXQgJT4lCiAgZ3JvdXBfYnkocmVwdW5pdCkgJT4lCiAgdGFsbHkoKSAlPiUKICBhcnJhbmdlKG4pICU+JQogIHdyaXRlX2NzdigiY3N2X291dHB1dHMvZGF0YXNldF9zcHBfd29fanV2cy5jc3YiKQogIApgYGAKS2VlcGluZyBqdXN0IHRoZSBqdXZlbmlsZXMgZnJvbSB0aG9zZSB0aHJlZSBzcGVjaWVzLCB3ZSBoYXZlIGEgdG90YWwgb2YgMSw1MzAgc2FtcGxlcyBmcm9tIDU0IHNwZWNpZXMuCgoKIyMgRG93bnNhbXBsZQoKV2hhdCBpZiBJIHRha2UgYSBtYXhpbXVtIG9mIDMyIHNhbXBsZXMgcGVyIHNwZWNpZXM/Cih1c2Ugc2V0LnNlZWQgdG8gZ2V0IHJlcHJvZHVjaWJsZSByZXN1bHRzISkKYGBge3IgZG93bnNhbXBsZX0KIyB3aGljaCBzcGVjaWVzIGhhdmUgZmV3ZXIgdGhhbiAzMiBzYW1wbGVzPwpzbV9ncnBzIDwtIGRhdGFzZXQgJT4lCiAgZ3JvdXBfYnkoY29sbGVjdGlvbikgJT4lCiAgdGFsbHkoKSAlPiUKICBhcnJhbmdlKG4pICU+JQogIGZpbHRlcihuIDwgMzMpCgojIG1ha2UgYSAyLWNvbCBkYXRhZnJhbWUgd2l0aCBqdXN0IHRob3NlIGdyb3VwcwpzbV9kMiA8LSBkYXRhc2V0ICU+JQogIHNlbWlfam9pbiguLCBzbV9ncnBzKSAlPiUKICB1bmdyb3VwKCkKCiMgd2hpY2ggc3BlY2llcyBoYXZlIG1vcmUgdGhhbiAzMiBzYW1wbGVzPwpscmdfZ3JwcyA8LSBkYXRhc2V0ICU+JQogIGdyb3VwX2J5KGNvbGxlY3Rpb24pICU+JQogIHRhbGx5KCkgJT4lCiAgYXJyYW5nZShuKSAlPiUKICBmaWx0ZXIobiA+IDMyKQogIAojIGRvd25zYW1wbGUgdGhvc2UgZ3JvdXBzCnNldC5zZWVkKDUpCmRvd25fc2FtIDwtIGRhdGFzZXQgJT4lCiAgc2VtaV9qb2luKC4sIGxyZ19ncnBzKSAlPiUKICBncm91cF9ieShjb2xsZWN0aW9uKSAlPiUKICBzYW1wbGVfbiguLCAzMiwgcmVwbGFjZSA9IEZBTFNFKSAlPiUKICB1bmdyb3VwKCkKCiMgZmluaXNoIHRoZSBzZXQuc2VlZApzZXQuc2VlZChOVUxMKQoKIyBhbmQgYWRkIHRoZSBkYXRhIGZyb20gdGhlIG90aGVyIGdyb3VwcyBiYWNrIGludG8gdGhlIGRhdGFmcmFtZQpkb3duX2RhdGEgPC0gc21fZDIgJT4lCiAgYmluZF9yb3dzKGRvd25fc2FtKSAjJT4lCiAgIyBncm91cF9ieShjb2xsZWN0aW9uKSAlPiUKICAjIHRhbGx5KCkgJT4lCiAgIyBhcnJhbmdlKG4pCmBgYAoKMTAxMCB0b3RhbCBzYW1wbGVzCjU0IHNwZWNpZXMKCgojIyBTZWxmLWFzc2lnbm1lbnQKCk5vdyBkbyB0aGUgc2VsZi1hc3NpZ25tZW50OgpgYGB7cn0KYXNzaWduX2Rvd24gPC0gc2VsZl9hc3NpZ24oZG93bl9kYXRhLCBnZW5fc3RhcnRfY29sID0gNSkKYGBgCgpBc3NpZ25tZW50IGFjY3VyYWN5PyAgCmBgYHtyfQphc3NpZ25fZG93biAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC45NSkgJT4lCiAgbXV0YXRlKGFjY3VyYXRlID0gaWZfZWxzZShyZXB1bml0ID09IGluZmVycmVkX3JlcHVuaXQsIFRSVUUsIEZBTFNFKSkgJT4lCiAgZmlsdGVyKGFjY3VyYXRlID09IFRSVUUpICMlPiUKICAjZmlsdGVyKGNvbGxlY3Rpb24gPT0gImNhcm5hdHVzIikKCmBgYAoKYGBge3J9Cjk5My8xMDEwCmBgYAoKei1zY29yZXM/CmBgYHtyfQp6X291dGxpZXJzIDwtIGFzc2lnbl9kb3duICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuNSAmIHpfc2NvcmUgPCAtMykgJT4lCiAgYXJyYW5nZSh6X3Njb3JlKQoKel9vdXRsaWVycwpgYGAKVGhlcmUgYXJlIDEwIHNhbXBsZXMgd2l0aCB6LXNjb3JlcyA8IC0zLCBpbmNsdWRpbmcgNSBob3BraW5zaSBzYW1wbGVzLgoKTGV0J3MgcmVtb3ZlIHRob3NlLgpgYGB7cn0KZG93bl9kYXRhMiA8LSBkb3duX2RhdGEgJT4lCiAgdW5ncm91cCgpICU+JQogIGFudGlfam9pbiguLCB6X291dGxpZXJzKQpgYGAKClJlbW92aW5nIHRob3NlIGxlYXZlcyB1cyB3aXRoIDEwMDAgc2FtcGxlcy4KCgojIE1peHR1cmUgYXNzaWdubWVudCB3aXRoIG91dGxpZXJzPwoKSnVzdCB0byB0ZXN0IGl0IG91dCwgSSdtIGdvaW5nIHRvIHJlbW92ZSB0aGVzZSBvdXRsaWVycyBmcm9tIHRoZSBiYXNlbGluZSBhbmQgdGhlbiBwZXJmb3JtIHJ1YmlhcydzIG1peHR1cmUgYXNzaWdubWVudCB3aXRoIHRoZW0uCgpgYGB7cn0KIyByZWZlcmVuY2UKZG93bl9kYXRhMiA8LSBkb3duX2RhdGEyICU+JQogIHVuZ3JvdXAoKQoKIyBvdXRsaWVycyBmb3IgbWl4dHVyZSBhc3NpZ25tZW50CnpzIDwtIHpfb3V0bGllcnMgJT4lCiAgc2VsZWN0KGluZGl2KQoKanVzdF96cyA8LSBkb3duX2RhdGEgJT4lCiAgdW5ncm91cCgpICU+JQogIHJpZ2h0X2pvaW4oLiwgenMpICU+JQogIG11dGF0ZShzYW1wbGVfdHlwZSA9ICJtaXh0dXJlIikKCmBgYAoKTm93IHRoYXQgdGhlIGRhdGEgYXJlIHNlcGFyYXRlZCBhbmQgZm9ybWF0dGVkLCBkbyB0aGUgbWl4dHVyZSBhc3NpZ25tZW50CmBgYHtyfQptaXhfenMgPC0gaW5mZXJfbWl4dHVyZShyZWZlcmVuY2UgPSBkb3duX2RhdGEyLCBtaXh0dXJlID0ganVzdF96cywgZ2VuX3N0YXJ0X2NvbCA9IDUpCmBgYAoKYGBge3J9Cm1peF96cyRpbmRpdl9wb3N0ZXJpb3JzICU+JQogIGZpbHRlcihQb2ZaID4gMC41MCkKICAKYGBgCkludGVyZXN0aW5nISBPbmUgb2YgdGhlIGhvcGtpbnNpIGNvbWVzIHVwIGFzIGNhdXJpbnVzLi4uIGJ1dCB3aXRoIGEgei1zY29yZSBvZiAtMTQhIFdoYXQgaXMgaXQ/PyBUaGUgei1zY29yZXMgZm9yIHRoZSBvdGhlciBmaXNoIGFyZSBhbHNvIHByZXR0eSBleHRyYW9yZGluYXJ5IChub25lIGFyZSB3aXRoaW4gMiBzdGFuZGFyZCBkZXZpYXRpb25zIG9mIHRoZSBtZWFuKS4KClRha2UgYSBxdWljayBsb29rIGF0IHRoZSB0aHJlZSBhZGRpdGlvbmFsIGhvcGtpbnNpIGluIG1peHR1cmUgYXNzaWdubWVudDoKYGBge3J9CiMgcHJldmlvdXMgMTAgc2FtcGxlcyAKanVzdF96cwoKIyBwbHVzIHRyZXMgbWFzCmFkZF90aHJlZSA8LSBkb3duX2RhdGEgJT4lCiAgcmlnaHRfam9pbiguLCB0cmVzX21hcykgJT4lCiAgbXV0YXRlKHNhbXBsZV90eXBlID0gIm1peHR1cmUiKQoKIyBjb21iaW5lIHRob3NlIGludG8gb25lIG1peHR1cmUgbGlzdAp0aGlydGVlbiA8LSBiaW5kX3Jvd3MoanVzdF96cywgYWRkX3RocmVlKQoKIyByZW1vdmUgdGhlIHRyZXMgbWFzIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhZnJhbWUKbWl4X3JlZiA8LSBkb3duX2RhdGEyICU+JQogIGFudGlfam9pbiguLCB0cmVzX21hcykKCiMgTm93IGRvIHRoZSBtaXh0dXJlIGFzc2lnbm1lbnQKbWl4MiA8LSBpbmZlcl9taXh0dXJlKHJlZmVyZW5jZSA9IG1peF9yZWYsIG1peHR1cmUgPSB0aGlydGVlbiwgZ2VuX3N0YXJ0X2NvbCA9IDUpCgpgYGAKVGFrZSBhIGxvb2sgYXQgdGhvc2UgcmVzdWx0cwpgYGB7cn0KdGhpcnRlZW4gJT4lCiAgZmlsdGVyKHJlcHVuaXQgPT0gImhvcGtpbnNpIikKCm1peDIkaW5kaXZfcG9zdGVyaW9ycyAlPiUKICBmaWx0ZXIoUG9mWiA+IDAuNTApICU+JQogICMgZmlsdGVyKG1peHR1cmVfY29sbGVjdGlvbiA9PSAiaG9wa2luc2kiKSAlPiUKICAjIGZpbHRlcihyZXB1bml0ID09ICJjYXVyaW51cyIpICU+JQogICMgc2VsZWN0KHpfc2NvcmUpCiAgZmlsdGVyKG1peHR1cmVfY29sbGVjdGlvbiA9PSByZXB1bml0KQogIApgYGAKV2lsZCEgU28gdGhyZWUgb2YgdGhlIGhvcGtpbnNpIGFzc2lnbiB0byBjYXVyaW51cywgYnV0IHdpdGggcmVhbGx5IHJlYWxseSBsb3cgei1zY29yZXMuCkkgdGhpbmsgdGhpcyBpcyBhY3R1YWxseSBpbnRlcmVzdGluZyBlbm91Z2ggdG8gaW5jbHVkZSBhcyBhIHNtYWxsIGFuYWx5c2lzIGluIHRoZSBtZXRob2RzL3Jlc3VsdHMuCgoKSW4gYWRkaXRpb24sIGxldCdzIGNyZWF0ZSBhIHNpbmdsZSByZXBvcnRpbmcgdW5pdCBmb3IgZ29waGVyL2JsYWNrLWFuZC15ZWxsb3cKCgojIyBzaW5nbGUgR0JZIHJlcG9ydGluZyB1bml0CgpTaW5jZSBhbGwgb2YgdGhlIG1pc2Fzc2lnbm1lbnRzIGFyZSBHQlksIG1ha2UgYSBzaW5nbGUgcmVwb3J0aW5nIHVuaXQuCgpgYGB7cn0KIyBjaGFuZ2UgdGhlIGNhcm5hdHVzIHJlcG9ydGluZyB1bml0IHRvIGNocnlzb21lbGFzCmdieV9yZXB1XzJjb2wgPC0gZG93bl9kYXRhMiAlPiUKICBtdXRhdGUocmVwdW5pdCA9IGlmZWxzZShyZXB1bml0ID09ICJjYXJuYXR1cyIsICJjaHJ5c29tZWxhcyIsIHJlcHVuaXQpKQoKIyBjb25maXJtIHRoYXQgdGhlIHJlcHVuaXQgaXMgY2hhbmdlZCBidXQgdGhlIGNvbGxlY3Rpb24gaXMgbm90LgpnYnlfcmVwdV8yY29sICU+JQogIGZpbHRlcihjb2xsZWN0aW9uID09ICJjYXJuYXR1cyIpCmBgYAoKTm93IHRyeSBzZWxmLWFzc2lnbm1lbnQgd2l0aCB0aGUgc2luZ2xlIHJlcG9ydGluZyB1bml0CmBgYHtyfQpnYnlfcmVwdV9hc3NpZ25lZCA8LSBnYnlfcmVwdV8yY29sICU+JQogIHNlbGZfYXNzaWduKC4sIGdlbl9zdGFydF9jb2wgPSA1KQoKYGBgCgpBY2N1cmFjeT8KYGBge3J9CmdieV9yZXB1X2Fzc2lnbmVkICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuOTUpICU+JQogIGZpbHRlcihyZXB1bml0ID09IGluZmVycmVkX3JlcHVuaXQpCmBgYAoKYGBge3J9Cjk5Mi8xMDAwCmBgYAoKYGBge3J9CmdieV9yZXB1X2Fzc2lnbmVkICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuNSAmIHNjYWxlZF9saWtlbGlob29kIDwgMC45NSkKYGBgCkFsbCBhc3NpZ25tZW50cyBiZWxvdyB0aGUgOTUlIHRocmVzaG9sZCB3ZXJlIGdvcGhlci9ibGFjay1hbmQteWVsbG93LgoKV2hhdCBhYm91dCB6LXN0YXRpc3RpY3M/CmBgYHtyfQpnYnlfcmVwdV9hc3NpZ25lZCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC41ICYgel9zY29yZSA8IC0zKQoKb3V0aWVzIDwtIGdieV9yZXB1X2Fzc2lnbmVkICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoc2NhbGVkX2xpa2VsaWhvb2QgPiAwLjUgJiB6X3Njb3JlIDwgLTMpCgojIHRyZXNfbWFzIDwtIG91dGllcyAlPiUKIyAgIHNlbGVjdChpbmRpdikgJT4lCiMgICB1bmdyb3VwKCkKYGBgClRocmVlIGFkZGl0aW9uYWwgaG9wa2luc2ksIGFzIGJlZm9yZS4KCldoYXQgd2VyZSB0aGUgei1zY29yZXMgZm9yIHRoZXNlIGhvcGtpbnNpIGluIHRoZSBwcmV2aW91cyBzZWxmLWFzc2lnbm1lbnQ/CmBgYHtyfQphc3NpZ25fZG93biAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHNjYWxlZF9saWtlbGlob29kID4gMC41ICYgcmVwdW5pdCA9PSAiaG9wa2luc2kiKSAlPiUKICBhcnJhbmdlKHpfc2NvcmUpICU+JQogIHNlbGVjdChpbmRpdiwgel9zY29yZSkgJT4lCiAgdW5ncm91cCgpCgpgYGAKTm90IHN1cmUgd2hhdCB0byBkbyBhYm91dCB0aGlzLiBTaG91bGQgSSBoYXZlIGxlZnQgaW4gdGhlIHRocmVlIGhvcGtpbnNpIHRoYXQgb25seSBiZWNhbWUgcHJvYmxlbWF0aWMgdGhlIHNlY29uZCB0aW1lIGFyb3VuZD8gT3IgY2FuIEkganVzdGlmeSBpdGVyYXRpbmcgYmVjYXVzZSB0aGUgei1zdGF0aXN0aWMgaXMgYmFzZWQgb24gdGhlIG1lYW4gb2YgdGhlIGRhdGEsIHNvIGlmIEkgaGF2ZSBjaGFuZ2VkIHRoZSBnZW5vdHlwZXMgdGhhdCBhcmUgdmFsaWQgaG9wa2luc2ksIHRoZW4gdGhlIG1lYW4gaGFzIGNoYW5nZWQsIGFuZCB0aHVzLCBpdCBpcyB1bnN1cnByaXNpbmcgdGhhdCBhZGRpdGlvbmFsIHNhbXBsZXMgYXJlIG5vdyBvdXRsaWVycy4KClRvIGJlIGNvbnNlcnZhdGl2ZSwgSSB0aGluayBpdCBtYWtlcyBzb21lIHNlbnNlIHRvIHJlbW92ZSB0aGVzZSBhZGRpdGlvbmFsIHRocmVlIGZpc2guCgoKIyMgT25jZSBtb3JlLCBhZnRlciByZW1vdmluZyB0aG9zZSBob3BraW5zaQoKYGBge3J9CmRvd25fZGF0YTMgPC0gZ2J5X3JlcHVfMmNvbCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYW50aV9qb2luKC4sIG91dGllcywgYnkgPSAiaW5kaXYiKQpgYGAKCgpTZWxmLWFzc2lnbm1lbnQgb25jZSBhZ2FpbiwgdG8gdGVzdCB3aGV0aGVyIHdlIGNhbiBhY3R1YWxseSBlbGltaW5hdGUgdGhlIHNhbXBsZXMgd2l0aCB6LXN0YXRpc3RpY3MgPCAtMwoKYGBge3J9CmFzc2lnbmVkMyA8LSBzZWxmX2Fzc2lnbihkb3duX2RhdGEzLCBnZW5fc3RhcnRfY29sID0gNSkKYGBgCgpDaGVjayB0aGUgYXNzaWdubWVudHMgYW5kIGNoZWNrIHRoZSB6LXNjb3JlcwpgYGB7cn0KYXNzaWduZWQzICU+JQogIGZpbHRlcihzY2FsZWRfbGlrZWxpaG9vZCA+IDAuNSAmIHpfc2NvcmUgPCAtMykKYGBgCkNvb2wsIHNvIHRoZXJlIGlzIGEgcG9pbnQgYXQgd2hpY2ggdGhlIHNhbXBsZXMgYXJlIGFsbCBmYWxsaW5nIHdpdGhpbiB0aGUgZXhwZWN0ZWQgZGlzdHJpYnV0aW9uIG9mICJhY2N1cmF0ZSIgYXNzaWdubWVudHMuCgoKIyMgUGh5bG9nZW5ldGljIHRyZWVzCgpMZXQncyBncmFiIGluZm9ybWF0aW9uIGZvciB0aG9zZSBzYW1wbGVzIHNvIHRoYXQgSSBjYW4gbWFrZSB0aGUgdHJlZXMgd2l0aCB0aGVtLgpgYGB7cn0KY2xlYW5fc2FtcGxlcyA8LSBhc3NpZ25lZDMgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihjb2xsZWN0aW9uID09IGluZmVycmVkX2NvbGxlY3Rpb24pICU+JQogIHNlbGVjdChpbmRpdiwgY29sbGVjdGlvbikgJT4lCiAgdW5ncm91cCgpCmBgYAoKOTk3IHNhbXBsZXMgaW4gdG90YWwuCgoKUmVhZCBpbiBnZW5vdHlwZSBkYXRhIHdpdGggdGhlIEdUc2VxIHJ1biBudW1iZXIgYW5kIHRoZSBzYW1wbGUgaWRzCmBgYHtyfQpnZW5vcyA8LSByZWFkUkRTKCIuLi9uZXdfYmFzZWxpbmVfZGF0YS9wcm9jZXNzZWQvY2FsbGVkX2dlbm9zX25hX2V4cGxpY2l0LnJkcyIpCgpnZW5vc19ndHNlcSA8LSBnZW5vcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KE5NRlNfRE5BX0lELCBndHNlcV9ydW4sIGlkKSAlPiUKICB1bmdyb3VwKCkKYGBgCgoKYGBge3J9CiMgYXJlIHRoZXJlIHNhbXBsZXMgdGhhdCB3ZXJlIHJ1biBpbiBtdWx0aXBsZSBHVC1zZXEgcnVucz8KIyBpZiBzbywgSSB3YW50IHRvIGJlIGFibGUgdG8gc2VsZWN0IGp1c3Qgb25lIG9mIHRob3NlIHNhbXBsZXMgZm9yIHRoZSBiYW1saXN0CmNsZWFuX3NhbXBsZXMgJT4lCiAgbGVmdF9qb2luKC4sIGdlbm9zX2d0c2VxLCBieSA9IGMoImluZGl2IiA9ICJOTUZTX0ROQV9JRCIpKSAlPiUKICBncm91cF9ieShjb2xsZWN0aW9uKSAlPiUKICB1bmlxdWUoKSAlPiUKICBhcnJhbmdlKGluZGl2KSAlPiUKICBzZWxlY3QoaW5kaXYpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShpbmRpdikgJT4lCiAgdGFsbHkoKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCiAgCmBgYAoKRm9yIGJ1aWxkaW5nIHRoZSBwaHlsb2dlbmV0aWMgdHJlZXMsIEkgbmVlZCBhIGxpc3Qgb2Ygc2FtcGxlcyBhbmQgR1RzZXEgcnVucyB0byB1c2UgZm9yIEZyZWViYXllcy4gQW5kIGZvciBzYW1wbGVzIHRoYXQgd2VyZSBnZW5vdHlwZWQgdHdpY2UsIEkgd2FudCB0byBjaG9vc2UgdGhlICJiZXN0IiBnZW5vdHlwZS4KCk5PVEU6IHRoZXNlIGFyZSBOT1QgZHVwbGljYXRlcyB3aXRoaW4gbXkgc2VsZi1hc3NpZ25tZW50IGRhdGFzZXQsIHRoZXkgYXJlIGR1cGxpY2F0ZXMgaW4gYGNhbGxlZF9nZW5vc19uYV9leHBsaWNpdC5yZHNgIAoKYGBge3J9CmR1cGxpY2F0ZXMgPC0gYygiUjAwMTU3MCIsIlIwMTE5OTMiLCJSMDEyMTExIiwiUjAxMjEyNSIsICJSMDEyMjAxIikKCmR1cGwgPC0gYXMudGliYmxlKGR1cGxpY2F0ZXMpCmR1cHMgPC0gZHVwbCAlPiUKICByZW5hbWUoTk1GU19ETkFfSUQgPSB2YWx1ZSkgJT4lCiAgdW5ncm91cCgpCgpgYGAKCkNoZWNrIG91dCB0aGUgZHVwbGljYXRlIGdlbm90eXBlcwpgYGB7cn0KZHVwX2dlbm9zIDwtIGR1cHMgJT4lCiAgbGVmdF9qb2luKC4sIGdlbm9zKSAlPiUKICB1bmdyb3VwKCkKYGBgCgpOb3cgdGFrZSB0aGUgZ2Vub3R5cGUgd2l0aCB0aGUgaGlnaGVzdCB0b3RhbCByZWFkIGRlcHRoLiAgCmBgYHtyIHRha2UtanVzdC1vbmV9CiMgc2xvdy1pc2ggZnVuY3Rpb24gdG8gZ2V0IHRoZSB0b3RhbCByZWFkIGRlcHRoIGNvbHVtbgp0ZGVwdGggPC0gZnVuY3Rpb24oYSwgZCkgewogIGlmKGFueShpcy5uYShhKSkpIHsKICAgIHJldHVybihOQSkKICB9CiAgaWYoYVsxXT09YVsyXSkgewogICAgcmV0dXJuKGRbMV0pCiAgfSBlbHNlIHsKICAgIHJldHVybihkWzFdICsgZFsyXSkKICB9CiAgCn0KIyB0aGlzIHRha2VzIHRoZSBoaWdoZXN0IHJlYWQtZGVwdGggaW5zdGFuY2Ugb2YgZWFjaCBkdXBsaWNhdGVseS1nZW5vdHlwZWQgaW5kaXZpZHVhbC4Kb25lX2VhY2ggPC0gZHVwX2dlbm9zICU+JQogIGdyb3VwX2J5KE5NRlNfRE5BX0lELCBsb2N1cywgZ3RzZXFfcnVuKSAlPiUKICBtdXRhdGUodG90YWxfZGVwdGggPSB0ZGVwdGgoYWxsZWxlLCBkZXB0aCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKE5NRlNfRE5BX0lELCBsb2N1cywgdG90YWxfZGVwdGgsIGd0c2VxX3J1biwgZGVwdGgpICU+JQogIGdyb3VwX2J5KE5NRlNfRE5BX0lELCBsb2N1cykgJT4lCiAgbXV0YXRlKHJhbmsgPSAxOm4oKSkgJT4lIAogICN1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHJhbmsgPD0gMikKCmBgYAoKQ29uZmlybSB0aGF0IHRoZXJlJ3Mgb25seSBvbmUgaW5zdGFuY2Ugb2YgZWFjaCBzYW1wbGUsIGFuZCBsb29rIGF0IHRoZSBndHNlcSBydW4gYW5kIGlkIGluZm8gaGVyZQpgYGB7cn0Kb25lX2R1cCA8LSBvbmVfZWFjaCAlPiUKICBncm91cF9ieShOTUZTX0ROQV9JRCwgZ3RzZXFfcnVuLCBpZCkgJT4lCiAgdGFsbHkoKSAlPiUKICBmaWx0ZXIobiA8IDEwMCkgIyBjaG9vc2UgdGhlIHNhbXBsZSB3aXRoIGZld2VyIGhpZ2gtcmVhZC1kZXB0aCBsb2NpIHRvIHJlbW92ZQoKb25lX2R1cApgYGAKCk9rYXksIG5vdyByZW1vdmUgdGhvc2Ugc2FtcGxlcywgd2hpY2ggc2hvdWxkIGxlYXZlIHVzIHdpdGggb3VyIGRhdGFzZXQgZm9yIGJ1aWxkaW5nIHRyZWVzLgpgYGB7cn0KY2xlYW5fc2FtcGxlcyAlPiUKICBsZWZ0X2pvaW4oLiwgZ2Vub3NfZ3RzZXEsIGJ5ID0gYygiaW5kaXYiID0gIk5NRlNfRE5BX0lEIikpICU+JQogIGFudGlfam9pbiguLCBvbmVfZHVwKSAlPiUKICB1bmlxdWUoKSAlPiUKICBhcnJhbmdlKGNvbGxlY3Rpb24pICU+JQogIHdyaXRlX2NzdigiY3N2X291dHB1dHMvY2xlYW5fZ3RzZXFfaWRzX2Zvcl90cmVlcy5jc3YiKQoKYGBgCgoKIyMgY2FsY3VsYXRlIGFuZCBwbG90IGludCBoeiBmb3IgZWFjaCBzcGVjaWVzCgpJIHdhbnQgdG8gdXNlIHRoaXMgc2FtZSBkYXRhc2V0IG9mIDk5NyBpbmRpdmlkdWFscyBmb3IgY2FsY3VsYXRpbmcgaW50LWh6LgpgYGB7cn0KdDEgPC0gY2xlYW5fc2FtcGxlcyAlPiUKICBsZWZ0X2pvaW4oZG93bl9kYXRhMykgJT4lCiAgZ3JvdXBfYnkoaW5kaXYsIGNvbGxlY3Rpb24pICU+JQogIHNlbGVjdCgtc2FtcGxlX3R5cGUsIC1yZXB1bml0KSAlPiUKICBnYXRoZXIobG9jdXMsIGFsbGVsZSwgMzoxODIpICU+JQogIHVuZ3JvdXAoKSAlPiUgIyBuZWVkIHRvIHJlbW92ZSB0aGUgLjEgYW5kIC4yIG9uIHRoZSBsb2NpCiAgc2VwYXJhdGUobG9jdXMsIGMoIkxvY3VzIiwgImdlbmUuY29weSIpLCBzZXAgPSAiWy5dIikKYGBgCgpgYGB7ciBjb21wdXRlLWludC1oenN9CmludF9oeiA8LSB0MSAlPiUgCiAgZ3JvdXBfYnkoY29sbGVjdGlvbiwgaW5kaXYsIExvY3VzKSAlPiUgCiAgc3VtbWFyaXNlKGh6ID0gYWxsZWxlWzFdIT1hbGxlbGVbMl0pICU+JSAKICBmaWx0ZXIoIWlzLm5hKGh6KSkgJT4lIAogIGdyb3VwX2J5KGluZGl2LCBjb2xsZWN0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKG51bV9sb2MgPSBuKCksIG51bV9oeiA9IHN1bShoeiksIGZyYWN0X2h6ID0gbnVtX2h6IC8gbnVtX2xvYykKCmBgYAoKIyMgV2hhdCBhYm91dCBtYWtpbmcgYSBzZXJpZXMgb2YgYm94cGxvdHM/CgpJIHdhbnQgdG8gc2V0IHRoZSBzcGVjaWVzIHBoeWxvZ2VuZXRpY2FsbHkgcmF0aGVyIHRoYW4gYWxwaGFiZXRpY2FsbHk6CmBgYHtyfQojIHNldCB0aGUgbGV2ZWxzIGV4cGxpY2l0bHkKaW50X2h6JGNvbGxlY3Rpb24gPC0gZmFjdG9yKGludF9oeiRjb2xsZWN0aW9uLCBsZXZlbHMgPSBjKCJhdHJvdmlyZW5zIiwgImNocnlzb21lbGFzIiwgImNhcm5hdHVzIiwgImNhdXJpbnVzIiwgIm1hbGlnZXIiLCAibmVidWxvc3VzIiwgImRhbGxpaSIsInJhc3RyZWxsaWdlciIsICJhdXJpY3VsYXR1cyIsICJzYXhpY29sYSIsICJzZW1pY2luY3R1cyIsICJlbG9uZ2F0dXMiLCAibWluaWF0dXMiLCAicGlubmlnZXIiLCAib2N1bGF0dXMiLCAiY29uc3RlbGxhdHVzIiwgInVtYnJvc3VzIiwgInJvc2FjZXVzIiwgImNobG9yb3N0aWN0dXMiLCAiZW5zaWZlciIsICJiYWJjb2NraSIsICJuaWdyb2NpbmN0dXMiLCAicnVicml2aW5jdHVzIiwgInNlcnJpY2VwcyIsICJydWZ1cyIsICJvdmFsaXMiLCAiaG9wa2luc2kiLCAicnVmaW5hbnVzIiwgIm1vc2VyaSIsICJqb3JkYW5pIiwgInBhdWNpc3BpbmlzIiwgImdvb2RlaSIsICJsZXZpcyIsICJlbnRvbWVsYXMiLCAibXlzdGludXMiLCAiZGlhY29udXMiLCAiZmxhdmlkdXMiLCAic2VycmFub2lkZXMiLCAibWVsYW5vcHMiLCAicnViZXJyaW11cyIsICJhdXJvcmEiLCAiZGlwbG9wcm9hIiwgIm1lbGFub3N0b211cyIsICJyZWVkaSIsICJjcmFtZXJpIiwgInBvbHlzcGluaXMiLCAiYWx1dHVzIiwgIm1lbGFub3N0aWN0dXMiLCAiYWxldXRpYW51cyIsICJlbXBoYWV1cyIsICJ3aWxzb25pIiwgInphY2VudHJ1cyIsICJwcm9yaWdlciIsICJib3JlYWxpcyIpKQoKIyBjaGVjayB0aGF0IHRoZSBsZXZlbHMgc3R1Y2sKbGV2ZWxzKGludF9oeiRjb2xsZWN0aW9uKQoKIyBub3cgYm94cGxvdCBpdApib3gyIDwtIGdncGxvdChpbnRfaHopICsKICBnZW9tX2JveHBsb3QoYWVzKHggPSBjb2xsZWN0aW9uLCB5ID0gZnJhY3RfaHopLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB0aGVtZV9idygpICsKICB4bGFiKCJTcGVjaWVzIikgKwogIHlsYWIoIkludGVybmFsIGhldGVyb3p5Z29zaXR5IikKCgpib3gyICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpCiAgKSArCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkKCmdnc2F2ZSgicGRmX291dHB1dHMvY2xlYW5faW50LWh6LWJveHBsb3QucGRmIiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCkKCmBgYApTdW1tYXJ5IFN0YXRpc3RpY3MKVGhlIGxvd2VyIGFuZCB1cHBlciBoaW5nZXMgY29ycmVzcG9uZCB0byB0aGUgZmlyc3QgYW5kIHRoaXJkIHF1YXJ0aWxlcyAodGhlIDI1dGggYW5kIDc1dGggcGVyY2VudGlsZXMpLiAKClRoZSB1cHBlciB3aGlza2VyIGV4dGVuZHMgZnJvbSB0aGUgaGluZ2UgdG8gdGhlIGxhcmdlc3QgdmFsdWUgbm8gZnVydGhlciB0aGFuIDEuNSB4IElRUiBmcm9tIHRoZSBoaW5nZSAod2hlcmUgSVFSIGlzIHRoZSBpbnRlci1xdWFydGlsZSByYW5nZSwgb3IgZGlzdGFuY2UgYmV0d2VlbiB0aGUgZmlyc3QgYW5kIHRoaXJkIHF1YXJ0aWxlcykuIFRoZSBsb3dlciB3aGlza2VyIGV4dGVuZHMgZnJvbSB0aGUgaGluZ2UgdG8gdGhlIHNtYWxsZXN0IHZhbHVlIGF0IG1vc3QgMS41IHggSVFSIG9mIHRoZSBoaW5nZS4gRGF0YSBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgd2hpc2tlcnMgYXJlIGNhbGxlZCAib3V0bHlpbmciIHBvaW50cyBhbmQgYXJlIHBsb3R0ZWQgaW5kaXZpZHVhbGx5LgpOb3cgd2hhdCBhYm91dCBhZGRpbmcgaW4gdGhlIHN1YmdlbmVyYSBhbmQgY29sb3JpbmcgdGhlIGJveGVzIGJ5IHRoYXQ/CgpNYWtlIGEgbGlzdCBvZiBzdWJnZW5lcmEgYW5kIHNwZWNpZXMgYW5kIHJlYWQgdGhhdCBpbgpgYGB7cn0Kc3ViZ2VuZXJhIDwtIHJlYWRfY3N2KCIuLi9kYXRhL3NlYmFzdGVzX3N1YmdlbmVyYS5jc3YiKSAlPiUKICB1bmdyb3VwKCkKICAKYGBgCgoKYGBge3J9CmludF9oel9zdWJnIDwtIGludF9oeiAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbGVmdF9qb2luKC4sIHN1YmdlbmVyYSwgYnkgPSBjKCJjb2xsZWN0aW9uIiA9ICJzcGVjaWVzIikpCgojIGFuZCBzZXQgdGhlIGxldmVscyBleHBsaWNpdGx5IGFnYWluCmludF9oel9zdWJnJGNvbGxlY3Rpb24gPC0gZmFjdG9yKGludF9oel9zdWJnJGNvbGxlY3Rpb24sIGxldmVscyA9IGMoImF0cm92aXJlbnMiLCAiY2hyeXNvbWVsYXMiLCAiY2FybmF0dXMiLCAiY2F1cmludXMiLCAibWFsaWdlciIsICJuZWJ1bG9zdXMiLCAiZGFsbGlpIiwicmFzdHJlbGxpZ2VyIiwgImF1cmljdWxhdHVzIiwgInNheGljb2xhIiwgImVtcGhhZXVzIiwgIndpbHNvbmkiLCAiemFjZW50cnVzIiwgInByb3JpZ2VyIiwgInNlbWljaW5jdHVzIiwgInJ1YnJpdmluY3R1cyIsICJsZXZpcyIsICJlbG9uZ2F0dXMiLCAibWluaWF0dXMiLCAicGlubmlnZXIiLCAiYmFiY29ja2kiLCAib2N1bGF0dXMiLCAiY29uc3RlbGxhdHVzIiwgInVtYnJvc3VzIiwgInJvc2FjZXVzIiwgImNobG9yb3N0aWN0dXMiLCAicnVmdXMiLCAiZW5zaWZlciIsICJkaXBsb3Byb2EiLCAibmlncm9jaW5jdHVzIiwgInNlcnJpY2VwcyIsICJvdmFsaXMiLCAiaG9wa2luc2kiLCAicnVmaW5hbnVzIiwgIm1vc2VyaSIsICJlbnRvbWVsYXMiLCAiYWx1dHVzIiwgImpvcmRhbmkiLCAicGF1Y2lzcGluaXMiLCAiZ29vZGVpIiwgIm15c3RpbnVzIiwgImRpYWNvbnVzIiwgImZsYXZpZHVzIiwgInNlcnJhbm9pZGVzIiwgIm1lbGFub3BzIiwgInJ1YmVycmltdXMiLCAiYXVyb3JhIiwgIm1lbGFub3N0b211cyIsICJjcmFtZXJpIiwgIm1lbGFub3N0aWN0dXMiLCAiYWxldXRpYW51cyIsICJib3JlYWxpcyIsICJyZWVkaSIsICJwb2x5c3BpbmlzIikpCgojIGNoZWNrIHRoYXQgdGhlIGxldmVscyBzdHVjawojbGV2ZWxzKGludF9oel9zdWJnJGNvbGxlY3Rpb24pCgpgYGAKClRyeSBjb2xvcmluZyB0aGUgYm94cGxvdCBieSB0aGUgc3ViZ2VuZXJhCgpJIG5lZWQgdG8gY29uZmlybSB0aGUgc3ViZ2VuZXJhIGFmZmlsaWF0aW9ucywgYnV0IEkgdGhpbmsgdGhhdCBjb3VsZCBlbmQgdXAgbG9va2luZyBwcmV0dHkgY29vbC4KSSBlbmRlZCB1cCB1c2luZyBhIGNvbWJvIG9mIExpIGV0IGFsLiAyMDA3LCBLZW5kYWxsIDIwMDAsIGFuZCBIeWRlIGFuZCBWZXR0ZXIgMjAwNy4KCkNoYW5nZSB0aGUgY29sb3JzOgpgYGB7cn0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCm15Y29sb3JzID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKG5hbWU9IkFjY2VudCIsIG4gPSA4KSkoMTQpCiAgCiNteWNvbG9ycyA9IGMoYnJld2VyLnBhbChuYW1lPSJTZXQxIiwgbiA9IDYpLCBicmV3ZXIucGFsKG5hbWU9IlNldDIiLCBuID0gOCkpCgpgYGAKClNldCB0aGUgc3ViZ2VuZXJhIHRvIHRoZSBvcmRlciBvZiB0aGUgZmFjdG9yIChzcGVjaWVzKQpgYGB7cn0KaW50X2h6MiA8LSBpbnRfaHpfc3ViZyAlPiUKICB1bmdyb3VwKCkKCmludF9oejIkc3ViZ2VudXMgPC0gZmFjdG9yKGludF9oejIkc3ViZ2VudXMsIGxldmVscyA9IGMoIlB0ZXJvcG9kdXMiLCAiQWxsb3NlYmFzdGVzIiwgIkhpc3BhbmlzY3VzIiwgIlJvc2ljb2xhIiwgIlNlYmFzdG9tdXMiLCAiU2ViYXN0aWNodGh5cyIsICJTZWJhc3RvY2FydXMiLCAiQWN1dG9tZW50dW0iLCAiU2ViYXN0b2RlcyIsICJTZWJhc3Rvc29tdXMiLCAiU2ViYXN0b3B5ciIsICJFb3NlYmFzdGVzIiwgIlphbG9weXIiLCAidW5jbGFzc2lmaWVkIikpCgpgYGAKCgpgYGB7cn0KCiMgbm93IGJveHBsb3QgaXQKYm94MyA8LSBnZ3Bsb3QoaW50X2h6MikgKwogIGdlb21fYm94cGxvdChhZXMoeCA9IGNvbGxlY3Rpb24sIHkgPSBmcmFjdF9oeiwgZmlsbCA9IHN1YmdlbnVzKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgdGhlbWVfYncoKSArCiAgeGxhYigiU3BlY2llcyIpICsKICB5bGFiKCJJbnRlcm5hbCBoZXRlcm96eWdvc2l0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycykKCgpib3gzICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSAxMiksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpCiAgKQojKwogICNndWlkZXMoZmlsbCA9IEZBTFNFKSAKCmdnc2F2ZSgicGRmX291dHB1dHMvaW50LWh6LWJveHBsb3Qtc3ViZ2VuZXJhX3YyLnBkZiIsIGhlaWdodCA9IDgsIHdpZHRoID0gMTApCgpgYGAKCldlIGNvdWxkIGFsc28gaW1hZ2luZSBvcmRlcmluZyB0aGUgc3BlY2llcyBhY2NvcmRpbmcgdG8gdGhlaXIgaW50ZXJuYWwgaGV0ZXJvenlnb3NpdHk6CgpgYGB7cn0KbGlicmFyeShmb3JjYXRzKQoKYm94NCA8LSBpbnRfaHoyICU+JQogIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyKGNvbGxlY3Rpb24sIGZyYWN0X2h6LCBmdW4gPSBtZWRpYW4sIC5kZXNjID1UUlVFKSwgZnJhY3RfaHosIGZpbGwgPSBzdWJnZW51cykpICsKICBnZW9tX2JveHBsb3QocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgdGhlbWVfYncoKSArCiAgeGxhYigiU3BlY2llcyIpICsKICB5bGFiKCJJbnRlcm5hbCBoZXRlcm96eWdvc2l0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbG9ycykKCmJveDQgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDEyKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkKICApICMrCiAgI2d1aWRlcyhmaWxsID0gRkFMU0UpCgpnZ3NhdmUoInBkZl9vdXRwdXRzL2ludC1oei1ib3hwbG90LW9yZGVyZWQucGRmIiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMCkKCmBgYAoKIyMgQ2FsY3VsYXRlIHRoZSByZWR1Y3Rpb24gaW4gaGV0ZXJvenlnb3NpdHkgaW4gY29tcGFyaXNvbiB0byBTLiBhdHJvdmlyZW5zCgpgYGB7cn0KaW50X2h6ICU+JQogIGdyb3VwX2J5KGNvbGxlY3Rpb24pICU+JQogIHN1bW1hcmlzZShhdmVfaHogPSBtZWFuKGZyYWN0X2h6KSkgJT4lCiAgYXJyYW5nZShkZXNjKGF2ZV9oeikpICU+JQogIG11dGF0ZShkaWZmX2h6ID0gKDAuNDU3ODEwNTUtYXZlX2h6KSkgIyBpZGVhbGx5IEkgd291bGQgbW9kaWZ5IHRoaXMgdG8gcmVmZXIgZGlyZWN0bHkgdG8gdGhlIHZhbHVlIGZvciBhdHJvdmlyZW5zCmBgYAoKUy4gY2hyeXNvbWVsYXMgcmV0YWlucyB0aGUgZ3JlYXRlc3QgaHogKDAuNDA5KSB3aGVyZWFzIFMuIHJ1YnJpdmluY3R1cyBoYXMgdGhlIHNtYWxsZXN0IGFtb3VudCBvZiB2YXJpYXRpb24gYXQgdGhlc2UgbWFya2VycyAoMC4wMTIpLg==